import type { H3Event } from "h3";
import { HTTPError, getQuery } from "h3";
import { logger } from "../helper/logger.ts";
import { verifySignatureHeader } from "@asteres/signature";

type SignatureOptions = {
  getSecretkeyByAppid: (appid: string) => Promise<string>;
  ignoredPaths?: string[];
  prefix?: string;
};

const signature = (config: SignatureOptions) => {
  return async (e: H3Event, next: () => any) => {
    let signatureHeader = e.req.headers.get("X-Signature");
    let errmsg;
    const ignoredPaths = config.ignoredPaths || [];
    let reqPath = e.url.pathname;
    reqPath = reqPath.replace(config.prefix || "", "");
    if (!ignoredPaths.includes(reqPath)) {
      let appid;
      if (!signatureHeader) {
        errmsg = "Missing signature header";
      } else {
        let body;
        const method = e.req.method;
        const contentType = e.req.headers.get("content-type") || "";
        if (contentType.includes("application/json") && method === "POST") {
          body = await e.req.text();
        }
        const verify = await verifySignatureHeader({
          headerValue: signatureHeader,
          getSecretkeyByAppid: config.getSecretkeyByAppid,
          url: reqPath,
          method,
          body,
          query: getQuery(e),
        });
        errmsg = verify.message;
        appid = verify.appid;
      }
      if (errmsg && errmsg !== "success") {
        logger.warn({ msg: errmsg, name: "signature" });
        throw new HTTPError("Invalid signature", {
          status: 403,
          statusText: "Forbidden",
        });
      }
      e.context.appid = appid;
    }
    return await next();
  };
};

export default signature;
